#!/usr/bin/python

# TODO:
# - import should be idempotent.
# - modify the real datastore: can't use remote_api because of the django vs
# appengine model issue. hm. maybe running this as a view is the best way?
# - make this work as a view, for per-user import/export.  How to upload a file?
# javascript? appengine can't access the filesystem right? use blobstore? 50M
# limit -- how big a file can I upload (via web form) without blobstore?
# blobstore upload: app can do "additional form processing", including accessing
# the blob?
# Export: no need for blobstore, just return the csv to the browser.  User can
# "Save As.."  Better to use the right http headers so it's seen as a file to
# download.
# Import:
# <form action=%s method="POST" enctype="multipart/form-data>
# <input type="file"></form>
# Django.forms.FileField()

# Template: Form with
#   Import: <Choose file> <Start Import>
#   Export: <Export> -> File download (dialog to Save as.. or browser download)
# view called import-export
#   code from here.
# put view into url config

# How to delete the appengine datastore and start fresh:
# /var/folders/8F/8FUXRTrEFH4gRNPilRudB++++TI/-Tmp-/django_sniffbook.datastore

# Clone the stuff in djangoappengine.main
import os, sys

# Add parent folder to sys.path, so we can import boot.
# App Engine causes main.py to be reloaded if an exception gets raised
# on the first request of a main.py instance, so don't add parent_dir multiple
# times.

#parent_dir = os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
parent_dir = os.path.abspath('common-apps')
if parent_dir not in sys.path:
    sys.path.insert(0, parent_dir)

# Remove the standard version of Django
if 'django' in sys.modules and sys.modules['django'].VERSION < (1, 2):
    print 'Removing sys.django'
    for k in [k for k in sys.modules
              if k.startswith('django\.') or k == 'django']:
        del sys.modules[k]

# And stuff from appcfg.py.  Probably running appcfg won't need this.
appcfg_file = '/usr/local/bin/appcfg.py'
DIR_PATH = os.path.abspath(os.path.dirname(os.path.realpath(appcfg_file)))
EXTRA_PATHS = [
  DIR_PATH,
  os.path.join(DIR_PATH, 'lib', 'antlr3'),
  #os.path.join(DIR_PATH, 'lib', 'django'),  # wrong django.
  os.path.join(DIR_PATH, 'lib', 'ipaddr'),
  os.path.join(DIR_PATH, 'lib', 'webob'),
  os.path.join(DIR_PATH, 'lib', 'yaml', 'lib'),
]
sys.path = EXTRA_PATHS + sys.path


from djangoappengine import boot
boot.setup_threading()
boot.setup_project()
boot.setup_logging()

import django.core.handlers.wsgi
from google.appengine.ext.webapp import util
from django.conf import settings

# OR: export DJANGO_SETTINGS_MODULE=sniff.settings
#os.environ['DJANGO_SETTINGS_MODULE'] = 'sniffbook.settings'

from inventory.models import Material, Component
from django.core.exceptions import ObjectDoesNotExist
import csv

def real_main():
  # Reset path and environment variables
  global path_backup
  try:
      sys.path = path_backup[:]
  except:
      path_backup = sys.path[:]
  os.environ.update(boot.env_ext)
  boot.setup_logging()

  mode = ''
  # TODO: more flags: filenames, materials or components
  while len(sys.argv):
    arg = sys.argv.pop(0)
    if arg == '--mode':
      mode = sys.argv.pop(0)

  if mode == 'import':
    #data = os.popen('wget "http://spreadsheets.google.com/pub?key=p2yhs3bJ71xGjUkwwWWYYRQ&output=csv&gid=0" -O -')
    data = open('exported-materials.csv')
    import_materials(data)
    data.close()

    data = open('exported-components.csv')
    import_components(data)
    data.close()

  if mode == 'export':
    export_materials('foo.csv')
    export_components('exported-components.csv')

#MATERIAL_SCHEME = 'chem._id,chem.bottle_num,chem.name,chem.notes,chem.ml_on_hand,chem.substantivity,bottle.dilution,chem.price_ml,extra.jnd,extra.url,extra.tags,extra.source_notes'
MATERIAL_SCHEME = 'chem.name,chem.bottle_num,chem.notes,chem.ml_on_hand,chem.substantivity,chem.price_ml'

#COMPONENT_SCHEME='comp._id,comp.accord_id,comp.component_id,comp.amount,comp.dilution'
COMPONENT_SCHEME='comp.accord_name,comp.component_name,comp.amount,comp.dilution'

def export_materials(filename):
  fp = open(filename, 'w')
  fp.write(MATERIAL_SCHEME + '\n')
  writer = csv.writer(fp)
  mats = Material.objects.all()
  for material in mats:
    data = [
             material.name,
             material.bottle_num,
             material.notes,
             material.ml_on_hand,
             material.substantivity,
             material.price_ml,
             ]
    writer.writerow(data)
  del writer

def export_components(filename):
  fp = open(filename, 'w')
  fp.write(COMPONENT_SCHEME + '\n')
  writer = csv.writer(fp)
  comps = Component.objects.all()
  for comp in comps:
    data = [ 
             comp.accord.name,
             comp.component.name,
             comp.amount,
             comp.dilution,
             ]
    writer.writerow(data)
  del writer

def import_components(data):
  """Import each row as a Material."""
  reader = csv.reader(data)
  scheme = reader.next()

  for d in reader:
    if len(d) < 2:
      continue
    (accord_name, component_name, amount, dilution) = d
    print d
    try:
      accord = Material.objects.get(name=accord_name)
      material = Material.objects.get(name=component_name)
    except ObjectDoesNotExist:
      # TODO maybe make and save new material?
      print 'Did not find material (%s, %s) skipping.' % (accord_name,
                                                          component_name)
      continue
    component = Component()
    # FIXME how to set reference? is this right?
    component.accord = accord
    component.component = material
    # Hooray for python type conversions?
    component.amount = amount
    component.dilution = dilution
    component.save()
    if not accord.is_accord:
      accord.is_accord = True
      accord.save()


def import_materials(data):
  """Import each row as a Material."""
  reader = csv.reader(data)
  scheme = reader.next()

  # Assume name is the first column
  name_ix = 0

  for d in reader:
    if len(d) < 2:
      continue
    else:
      name = d[name_ix]
      print name
      is_new = False
      try:
        material = Material.objects.get(name=name)
      except ObjectDoesNotExist:
        is_new = True
        material = Material()
        material.name = name
      #except MultipleObjectsReturned:
        # FIXME: look for multiple objects w/ same name.
        #print 'Ignoring Multiple objects for name ', name
        #continue
    for ix in range(len(d)):
      if d[ix]:
        (class_name, attr) = scheme[ix].split('.')
        # TODO: catch attribute error
        if class_name == 'chem':
          material.__setattr__(attr, d[ix])
        elif class_name == 'bottle':
          # We used to distinguish between these classes, but not anymore.
          material.__setattr__(attr, d[ix])
    material.save()

if __name__ == '__main__':
  real_main()
